package cn.jltx.support;


import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;

import java.util.List;

import cn.jltx.anima.DefaultHorizontalAnimator;
import cn.jltx.anima.FragmentAnimator;
import cn.jltx.constant.FragmentConstant;
import cn.jltx.helper.AnimatorHelper;
import cn.jltx.helper.LifecycleHelper;
import cn.jltx.utils.XqLog;

/**
 * @author jltxseo
 *         Created by junlintianxia on 2017/04/12.
 */

public class SupportFragment extends Fragment implements ISupportFragment{
    public static final String TAG = SupportFragment.class.getSimpleName();

    protected SupportAppCompatActivity mActivity;
    private int mContainerId;   // 该Fragment所处的Container的id
    protected boolean mLocking;
    private boolean mIsRoot;
    private Bundle mSaveInstanceState;

    //Fragment动画
    private FragmentAnimator mFragmentAnimator;
    private AnimatorHelper mAnimHelper;
    private static final long DEFAULT_ANIM_DURATION = 300L;

    private boolean mIsHidden = true;   // 用于记录Fragment show/hide 状态
    //是否可见
    private boolean mIsSupportVisible;
    private boolean mNeedDispatch = true;  //是否分发显示或者隐藏状态
    //标志是否进行进行懒加载，ture表示进行懒加载
    private boolean mIsFirstVisible = true;

    boolean mUserVisibleHint = false; //填坑，在FragmentStatePagerAdapter使用mUserVisibleHint的get和set值不一致的坑

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (activity instanceof SupportAppCompatActivity) {
            this.mActivity = (SupportAppCompatActivity) activity;
        } else {
            throw new RuntimeException(activity.toString() + "must extends SupportAppCompatActivity!");
        }
        dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONATTACH, null, false);

    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle bundle = getArguments();
        if(bundle != null){
            mIsRoot = bundle.getBoolean(FragmentConstant.FRAGMENTATION_ARG_IS_ROOT, false);
            mContainerId = bundle.getInt(FragmentConstant.FRAGMENTATION_ARG_CONTAINER);
        }

        if(savedInstanceState == null){
            if(mFragmentAnimator == null){
                mFragmentAnimator = onCreateFragmentAnimator();
            }
        }else {
            mSaveInstanceState = savedInstanceState;
            mFragmentAnimator = savedInstanceState.getParcelable(FragmentConstant.FRAGMENTATION_STATE_SAVE_ANIMATOR);  //获取旋转屏幕或者是内存后重建Acitivity保存的动画
            if(restoreInstanceState()){
                mIsHidden = savedInstanceState.getBoolean(FragmentConstant.FRAGMENTATION_STATE_SAVE_IS_HIDDEN);
            }
            if (mContainerId == 0) { // After strong kill, mContianerId may not be correct restored.
                mIsRoot = savedInstanceState.getBoolean(FragmentConstant.FRAGMENTATION_ARG_IS_ROOT, false);
                mContainerId = savedInstanceState.getInt(FragmentConstant.FRAGMENTATION_ARG_CONTAINER);
            }
        }

        if(restoreInstanceState()){
            // 解决重叠问题
            processRestoreInstanceState(savedInstanceState);
        }

        initAnim();
        dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONCREATE, savedInstanceState, false);

    }

    /**
     * 解决重叠问题
     * @param savedInstanceState
     */
    private void processRestoreInstanceState(Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            if (mIsHidden) {
                ft.hide(this);
            } else {
                ft.show(this);
            }
            ft.commit();
        }
    }
    /**
     * 内存重启后,是否让Fragmentation帮你恢复子Fragment状态
     * v7 support 24.0.0之前23.4.0不包括24.0.0的Fragment都是旋转后重叠的，24.0.0+之后就修复了
     * 这里控制是否需要开启解决重叠bug的解决方案
     */
    protected boolean restoreInstanceState() {
        return true;
    }

    /**
     *
     * @param transit  标志是否是跳转到下一个Fragment：
     *                 FragmentTransaction.TRANSIT_FRAGMENT_OPEN表示跳转到下一个Fragment;
     *                 FragmentTransaction.TRANSIT_FRAGMENT_CLOSE表示回退的方式即出栈
     * @param enter    标志是否是回到当前fragment
     *                 true表示回到当前Fragment
     *                 false表示离开该Fragment
     * @param nextAnim
     * @return
     */

    @Override
    public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {

        if (mLocking || mActivity.mPopMultipleNoAnim) { //这两种情况时不做动画
            if (transit == FragmentTransaction.TRANSIT_FRAGMENT_CLOSE && enter) {
                return mAnimHelper.getNoneAnimFixed();
            }
            return mAnimHelper.getNoneAnim();
        }
        if (transit == FragmentTransaction.TRANSIT_FRAGMENT_OPEN) {
            Log.i(TAG,"FragmentTransaction.TRANSIT_FRAGMENT_OPEN=>"+enter+":"+this.getClass().getSimpleName());
            if (enter) {
                if (mIsRoot){
                    Log.i(TAG,"onCreateAnimation根Fragment无动画=>"+this.getClass().getSimpleName());
                    return mAnimHelper.getNoneAnim();
                }
                Log.i(TAG,"onCreateAnimation.Fragment.mAnimHelper.enterAnim=>"+this.getClass().getSimpleName());
                return mAnimHelper.enterAnim;
            } else {
                Log.i(TAG,"onCreateAnimation.Fragment.mAnimHelper.popExitAnim=>"+this.getClass().getSimpleName());
                return mAnimHelper.popExitAnim;
            }
        } else if (transit == FragmentTransaction.TRANSIT_FRAGMENT_CLOSE) {
            Log.i(TAG,"FragmentTransaction.TRANSIT_FRAGMENT_CLOSE=>"+enter+":"+this.getClass().getSimpleName());
            if(enter){
                Log.i(TAG,"onCreateAnimation.Fragment.mAnimHelper.popEnterAnim=>"+this.getClass().getSimpleName());
            }else {
                Log.i(TAG,"onCreateAnimation.Fragment.mAnimHelper.exitAnim=>"+this.getClass().getSimpleName());
            }
            return enter ? mAnimHelper.popEnterAnim : mAnimHelper.exitAnim;
        } else {
            Log.i(TAG,"FragmentTransaction.TRANSIT_NONE=>"+this.getClass().getSimpleName());
            if ( enter) notifyNoAnim();
            return super.onCreateAnimation(transit, enter, nextAnim);
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mIsRoot) {
            outState.putBoolean(FragmentConstant.FRAGMENTATION_ARG_IS_ROOT, true);
        }
        outState.putInt(FragmentConstant.FRAGMENTATION_ARG_CONTAINER, mContainerId);
        outState.putParcelable(FragmentConstant.FRAGMENTATION_STATE_SAVE_ANIMATOR, mFragmentAnimator);
        if(restoreInstanceState()){
            outState.putBoolean(FragmentConstant.FRAGMENTATION_STATE_SAVE_IS_HIDDEN, isHidden());
        }
//        outState.putBoolean(Fragmentation.FRAGMENTATION_STATE_SAVE_IS_INVISIBLE_WHEN_LEAVE, mInvisibleWhenLeave);

        dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONSAVEINSTANCESTATE, outState, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONVIEWCREATED, savedInstanceState, false);
    }

    public boolean isIsRoot() {
        return mIsRoot;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        View view = getView();
        // 防止某种情况 上一个Fragment仍可点击问题
        if (view != null) {
            view.setClickable(true);
        }

        if(!isHidden() && (getUserVisibleHint())){
            if((getParentFragment() == null) || (getParentFragment() != null && !getParentFragment().isHidden())){
                mNeedDispatch = false;
                dispatchSupportVisible(true);
            }
        }
        dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONACTIVITYCREATED, savedInstanceState, false);
    }

    @Override
    public void loadRootFragment(int containerId, SupportFragment toFragment) {
        getFragmentImpl().loadRootFragment(getChildFragmentManager(),containerId,toFragment);
    }

    @Override
    public void loadMultipleRootFragment(int containerId, SupportFragment... toFragments) {
        loadMultipleRootFragment(containerId,0,toFragments);
    }

    @Override
    public void loadMultipleRootFragment(int containerId, int showPosition, SupportFragment... toFragments) {
        getFragmentImpl().loadMutipleRootFragment(getChildFragmentManager(),containerId,showPosition,toFragments);
    }

    @Override
    public void pop() {
        getFragmentImpl().back(getFragmentManager());
    }

    @Override
    public void popChild() {
        getFragmentImpl().back(getChildFragmentManager());
    }

    @Override
    public void startFragment(SupportFragment toFragment) {
        getFragmentImpl().dispatchStartTransaction(getFragmentManager(),this,toFragment,FragmentConstant.TYPE_ADD);
    }

    @Override
    public void startFragmentWithPop(SupportFragment toFragment) {
        getFragmentImpl().dispatchStartTransaction(getFragmentManager(),this,toFragment,FragmentConstant.TYPE_ADD_WITH_POP);
    }

    @Override
    public SupportFragment getTopFragment() {
        return getFragmentImpl().getTopFragment(getFragmentManager());
    }

    @Override
    public FragmentImpl getFragmentImpl() {
        return mActivity.getFragmentImpl();
    }

    @Override
    public void popFragmentTo(Class<?> fragmentClass, boolean includeSelf, Runnable afterPopTransactionRunnable) {
        popFragmentTo(fragmentClass.getName(),includeSelf,afterPopTransactionRunnable);
    }

    @Override
    public void popFragmentTo(String fragmentTag, boolean includeSelf, Runnable afterPopTransactionRunnable) {
        getFragmentImpl().popFragmentTo(fragmentTag,includeSelf,afterPopTransactionRunnable,mActivity.getSupportFragmentManager());
    }

    @Override
    public <T extends SupportFragment> T findChildFragment(Class<T> fragmentClass) {
        return getFragmentImpl().findStackFragment(getChildFragmentManager(),fragmentClass,null);
    }

    @Override
    public <T extends SupportFragment> T findChildFragment(String fragmentTag) {
        getFragmentImpl().checkNotNull(fragmentTag, "tag == null");
        return getFragmentImpl().findStackFragment(getChildFragmentManager(),null,fragmentTag);
    }

    @Override
    public <T extends SupportFragment> T findFragment(Class<T> fragmentClass) {
        return getFragmentImpl().findStackFragment(getFragmentManager(),fragmentClass,null);
    }

    @Override
    public <T extends SupportFragment> T findFragment(String fragmentTag) {
        getFragmentImpl().checkNotNull(fragmentTag, "tag == null");
        return getFragmentImpl().findStackFragment(getFragmentManager(),null,fragmentTag);
    }

    @Override
    public void showHideFragment(SupportFragment showFragment) {
        showHideFragment(showFragment,null);
    }

    @Override
    public void showHideFragment(SupportFragment showFragment, SupportFragment hideFragment) {
        getFragmentImpl().showHideFragment(getChildFragmentManager(),showFragment,hideFragment);
    }

    @Override
    public void replaceLoadRootFragment(int containerId, SupportFragment toFragment, boolean addToBack) {
        getFragmentImpl().replaceLoadRootTransaction(getChildFragmentManager(),containerId,toFragment,addToBack);
    }

    @Override
    public void replaceFragment(SupportFragment toFragment, boolean addToBack) {
        getFragmentImpl().replaceTransaction(this,toFragment,addToBack);
    }

    @Override
    public void onStart() {
        super.onStart();
        dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONSTART, null, false);
    }

    @Override
    public void onResume() {
        super.onResume();
        dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONRESUME, null, false);
        if(!mIsFirstVisible){ //懒加载过后
            if(!mIsSupportVisible && !isHidden() && getUserVisibleHint()){
                mNeedDispatch = false;
                dispatchSupportVisible(true);
            }
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONPAUSE, null, false);
        if(mIsSupportVisible && !isHidden() && getUserVisibleHint()){
            mNeedDispatch = false;
            dispatchSupportVisible(false);
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONSTOP, null, false);
        XqLog.d(TAG,"onStop."+this.getClass().getName());
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        XqLog.d(TAG,"onHiddenChanged.hidden:"+hidden+this.getClass().getName());
        if(isResumed()){
            dispatchSupportVisible(!hidden);
        }
    }

    /**
     * viewpager会回调到这里
     * @param isVisibleToUser
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        this.mUserVisibleHint = getUserVisibleHint();
        if(isResumed()){
            if(!mIsSupportVisible && isVisibleToUser){
                dispatchSupportVisible(true);
            }else if(mIsSupportVisible && !isVisibleToUser){
                dispatchSupportVisible(false);
            }
        }
    }

    @Override
    public boolean getUserVisibleHint() {
        return super.getUserVisibleHint() || mUserVisibleHint;
    }

    /**
     * 分发懒加载和是否可见事件回调
     * @param visible
     */
    private void dispatchSupportVisible(boolean visible){
        mIsSupportVisible = visible;
        if (!mNeedDispatch) {
            mNeedDispatch = true;
        } else {
            FragmentManager fragmentManager = getChildFragmentManager();
            if (fragmentManager != null) {
                List<Fragment> childFragments = fragmentManager.getFragments();
                if (childFragments != null) {
                    for (Fragment child : childFragments) {
                        Log.i("RRRRR", "子view分发dispatchSupportVisible--->");
                        if (child instanceof SupportFragment && !child.isHidden() && child.getUserVisibleHint()) {
                            ((SupportFragment) child).dispatchSupportVisible(visible);
                        }
                    }
                }
            }
        }

        if(visible){
            if(mIsFirstVisible){ //懒加载分发事件
                mIsFirstVisible = false;
                onLazyInitView(mSaveInstanceState);
                dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONLAZYINITVIEW,null,false);
            }

            onUserVisible();
            if(mActivity != null){
                mActivity.setFragmentClickable(true);
            }
            dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONSUPPORTVISIBLE, null, true);
        }else {
            onUserInvisible();
            dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONSUPPORTINVISIBLE, null, false);
        }

    }
    @Override
    public void onDestroyView() {
        mActivity.setFragmentClickable(true);
        super.onDestroyView();
        mIsFirstVisible = true;
        dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONDESTROYVIEW, null, false);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONDESTROY, null, false);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONDETACH, null, false);
    }

    /**
     * 所有继承BackHandledFragment的子类都将在这个方法中实现物理Back键按下后的逻辑
     * Activity捕捉到物理返回键点击事件后会首先询问Fragment是否消费该事件
     * 如果没有Fragment消息时Activity自己才会消费该事件
     */
    public  boolean onBackPressedSupport(){
        return false;
    }

    /**
     * 入栈动画 结束时,回调
     */
    protected void onEnterAnimationEnd(Bundle savedInstanceState) {
    }

    /**
     * Lazy initial，Called when fragment is first called.
     * <p>
     * 同级下的 懒加载 ＋ ViewPager下的懒加载  的结合回调方法
     */
    public void onLazyInitView(@Nullable Bundle savedInstanceState) {
        XqLog.d(TAG,"onLazyInitView:"+this.getClass().getName());
    }

    /**
     *  fragment可见
     * Called when the fragment is vivible.
     * <p>
     * Is the combination of  [onHiddenChanged() + onResume()/onPause() + setUserVisibleHint()]
     */
    public void onUserVisible() {
        XqLog.d(TAG,"onUserVisible."+this.getClass().getName());
    }

    /**
     * fragment不可见
     * Called when the fragment is invivible.
     * <p>
     * Is the combination of  [onHiddenChanged() + onResume()/onPause() + setUserVisibleHint()]
     */
    public void onUserInvisible() {
        XqLog.d(TAG,"onUserInvisible."+this.getClass().getName());
    }

    private void initAnim() {
        mAnimHelper = new AnimatorHelper(mActivity.getApplicationContext(), mFragmentAnimator);
        // 监听入栈动画结束(1.为了防抖动; 2.为了Fragmentation的回调所用)
        mAnimHelper.enterAnim.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                mActivity.setFragmentClickable(false);  // 开启防抖动
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                notifyEnterAnimEnd();
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }
        });
    }

    private void notifyNoAnim() {
        notifyEnterAnimationEnd(mSaveInstanceState);
        mActivity.setFragmentClickable(true);
    }

    /**
     * 入场动画结束时,回调
     */
    void notifyEnterAnimEnd() {
        notifyEnterAnimationEnd(null);
        mActivity.setFragmentClickable(true);
    }


    private void notifyEnterAnimationEnd(final Bundle savedInstanceState) {
        mActivity.getWindow().getDecorView().post(new Runnable() {
            @Override
            public void run() {
                onEnterAnimationEnd(savedInstanceState);
                dispatchFragmentLifecycle(LifecycleHelper.LIFECYLCE_ONENTERANIMATIONEND, savedInstanceState, false);
            }
        });
    }

    Bundle getSaveInstanceState() {
        return mSaveInstanceState;
    }

    public int getContainerId() {
        return mContainerId;
    }

    long getEnterAnimDuration() {
        if (mIsRoot) {
            return 0;
        }
        if (mAnimHelper == null) {
            return DEFAULT_ANIM_DURATION;
        }
        return mAnimHelper.enterAnim.getDuration();
    }

    long getExitAnimDuration() {
        if (mAnimHelper == null) {
            return DEFAULT_ANIM_DURATION;
        }
        return mAnimHelper.exitAnim.getDuration();
    }

    long getPopEnterAnimDuration() {
        if (mAnimHelper == null) {
            return DEFAULT_ANIM_DURATION;
        }
        return mAnimHelper.popEnterAnim.getDuration();
    }

    long getPopExitAnimDuration() {
        if (mAnimHelper == null) {
            return DEFAULT_ANIM_DURATION;
        }
        return mAnimHelper.popExitAnim.getDuration();
    }

    public void setFragmentAnimator(FragmentAnimator mFragmentAnimator) {
        this.mFragmentAnimator = mFragmentAnimator;
    }

    /**
     * 设定当前Fragmemt动画,优先级比在SupportActivity里高
     */
    protected FragmentAnimator onCreateFragmentAnimator() {
        return new DefaultHorizontalAnimator();
    }

    /**
     *统一调度片段的生命周期调用生命周期监听器
     * @param lifecycle
     * @param bundle
     * @param visible
     */
    private void dispatchFragmentLifecycle(int lifecycle, Bundle bundle, boolean visible) {
        if (mActivity == null) return;
        mActivity.dispatchFragmentLifecycle(lifecycle, SupportFragment.this, bundle, visible);
    }

}
